package com.privasphere.wikidoclet.dataTransport;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXParseException;

import com.privasphere.wikidoclet.util.WikiDocletCfg;

/**
 * That's an helper class to read the XML-file generated by the WikiDoclet
 * @author Christian Dubs
 *
 */
public class XmlReaderDOM implements XmlReadeable<WikiDocPageData> {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(XmlReaderDOM.class.getName());
	private static final String WIKI_DOCLET_XSD = "wikidoclet.xsd";

	private Document doc;
	private int childListLen = -1;
	private Element rootElement;
	
	private NodeList pageList;
	private String indexPageIdentifier;
	private List<WikiDocPageData> tmp = new LinkedList<WikiDocPageData>();
	
	/**
	 * just for debugging.
	 * @param args
	 */
	public static void main(String[] args){
		XmlReaderDOM myReader = new XmlReaderDOM();
		
		System.out.println("INDEX PAGE ATTRIBUTE: " + myReader.getIndexPageIdentifier());
		
		for(WikiDocPageData p : myReader.getParsedElements()){
			System.out.println("PAGE_TITLE: " + p.getTitleValue()); 
			System.out.println("PAGE_HASH: " + p.getHashValue());
			System.out.println("PAGE_TIME:  " + p.getTimeValue() + "\n");
		}
	}
	
	/**
	 * Default constructor
	 */
	public XmlReaderDOM(){
		//makes all initialization steps. At last it generates the pageList. --> List of page elements
		init();
	}
	
	private void init(){
        
        try {
        	WikiDocletCfg cfg = WikiDocletCfg.getInstance();
    		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    		docBuilderFactory.setValidating(false);
    		docBuilderFactory.setNamespaceAware(true);
    		
    		//check xml against scheme
    		SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
    		docBuilderFactory.setSchema(schemaFactory.newSchema(new Source[] { new StreamSource(getClass().getResourceAsStream(WIKI_DOCLET_XSD))}));

    		DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			docBuilder.setErrorHandler(new XmlReaderDOMErrorHandler());
			doc = docBuilder.parse(new File(cfg.getConfigValue(WikiDocletCfg.CFG_PAR_XML)));
			
			// normalize text representation
            doc.getDocumentElement().normalize();
            
            //That's the root element of the xml --> wikiDocletPage tag
            rootElement = doc.getDocumentElement();
            
            //getting the url of the indexpage
            indexPageIdentifier = rootElement.getAttribute(WikiDocletCfg.WIKI_DOCLET_INDEX_PAGE_NAME_ATTRIBUTE);
            
            //logging for debugging purposes
            LOGGER.trace("WikiDoclet XML File root element name: " + rootElement.getNodeName());
            
            //That's a list of all child nodes from the root node --> page tag
            pageList = doc.getDocumentElement().getChildNodes();
            
            //Represents the number of page elements in current xml file.
            childListLen = pageList.getLength();
            
	        //logging for debugging purposes
	        LOGGER.trace("XML PAGE LIST LENGTH: " + childListLen);

		} catch (ParserConfigurationException e) {
			LOGGER.error("XML-Reader parser configuration exception" , e);
		}
		catch (SAXParseException err) {
			LOGGER.error ("** Parsing error" + ", line " + err.getLineNumber () + ", uri " + err.getSystemId ());
			LOGGER.error(" " + err.getMessage ());
			
		}
		catch (IOException e) {
			LOGGER.error("XML Reader IOException" , e);
			System.exit(-1);
		}
		catch (Throwable t) {
			LOGGER.error("XML Reader has an error" , t);
			System.exit(-1);
		}
	}

	private String getNodeValues(Element pageElement, String tagName, int i) {
		NodeList nodeList;
		Element nodeElement;
		NodeList currentNodeTextNodeList;
		String tmpCurrentNodeValue;
		
		//------- getting value of element of current page element
		nodeList = pageElement.getElementsByTagName(tagName);
		nodeElement = (Element)nodeList.item(0);

		currentNodeTextNodeList = nodeElement.getChildNodes();
		
		tmpCurrentNodeValue = ((Node)currentNodeTextNodeList.item(0)).getNodeValue().trim();
		
		//logging for debugging purposes
		LOGGER.trace("XML DATA: " + nodeElement.getNodeName() + ": chars: " + tmpCurrentNodeValue.length());
		
		//------- end getting value of element
		
		return tmpCurrentNodeValue;
		
	}

	/**
	 * Method to get the indexPageUrl
	 * @return indexPageUrl - A String representing indexPageUrl
	 */
	public String getIndexPageIdentifier() {
		return indexPageIdentifier;
	}

	@Override
	public List<WikiDocPageData> getParsedElements() {
		Node pageNode;
		Element pageElement;
		WikiDocPageData myXMLLine;
		
		for(int i = 0; i < pageList.getLength(); ++i){
			pageNode = pageList.item(i);
	    	
	    	//logging for debugging purposes
	    	LOGGER.trace("PAGE " + i);
	    	
	    	if(pageNode.getNodeType() == Node.ELEMENT_NODE){
	    		pageElement = (Element)pageNode;
	    		myXMLLine = new WikiDocPageData();
	    		
	    		myXMLLine.setTitleValue(getNodeValues(pageElement, WikiDocletCfg.WIKI_DOCLET_XML_TITLE, i));
	    		myXMLLine.setContentValue(new StringBuilder(getNodeValues(pageElement, WikiDocletCfg.WIKI_DOCLET_XML_CONTENT, i)));
	    		myXMLLine.setHashValue(getNodeValues(pageElement, WikiDocletCfg.WIKI_DOCLET_XML_HASH, i));
	    		myXMLLine.setTimeValue(getNodeValues(pageElement, WikiDocletCfg.WIKI_DOCLET_XML_TIME, i));
	    		tmp.add(myXMLLine);
	    	}
    	}
		return tmp;
	}
}